/* 
 * File:   Trigonometrica.cpp
 * Author: jorgeorm
 * 
 * Created on 29 de agosto de 2011, 06:27 PM
 */

#include "Trigonometrica.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <iostream>


using namespace std;

const double pi=3.14159265;

Trigonometrica::Trigonometrica(int truncarEn ,int tamanoDatos) {
    
    truncar=truncarEn;
    tam_prueba=tamanoDatos;
    
    ptr_arrayBernoul= new double[(2*truncarEn)+1];
            
    ptr_arrayDatos=new double[tam_prueba];
     
    mat_Results= new double *[tam_prueba];
    mat_ResultsMcLauren= new long double * [tam_prueba];
    mat_Error_trunc = new long double * [tam_prueba];
    
    for(int idfilas =0;idfilas <tam_prueba; idfilas++)
    {
      mat_Results[idfilas]=new double[3];
      mat_ResultsMcLauren[idfilas]=new long double[3];
      mat_Error_trunc[idfilas] = new long double[3];
      for( int idCol=0; idCol<3; idCol++)
      {
          mat_Results[idfilas][idCol]=0.0;
          mat_ResultsMcLauren[idfilas][idCol]=0.0;
          mat_Error_trunc[idfilas][idCol]=0.0;
      }
    }
    
    ptr_output= fopen("resultadosTrigo.txt","wb+");   
}


Trigonometrica::~Trigonometrica() {

    for(int idy=0;idy<tam_prueba;idy++)
    {
        delete []mat_Results[idy];
        delete []mat_ResultsMcLauren[idy];
        delete []mat_Error_trunc[idy];

        mat_Results[idy]=NULL;
        mat_ResultsMcLauren[idy]=NULL;
        mat_Error_trunc[idy]=NULL;
    }
    
    delete mat_Results;
    delete mat_ResultsMcLauren;
    delete mat_Error_trunc;
    delete ptr_output;
    delete[] ptr_arrayDatos;
    ptr_arrayDatos=NULL;
    ptr_output=NULL;    
}

void Trigonometrica::inicializarDatosPrueba()
{
    srand(time(NULL));
    for(int i=0;i<tam_prueba;i++)
    {
        int potencia=((double)random()/(double)RAND_MAX)*10.0;
//        cout<<"Potencia: "<<potencia<<", ";
        ptr_arrayDatos[i]=((double)random()/(double)RAND_MAX)*pi*pow(-1,potencia);
//        cout<<"valorX["<<i<<"]: "<<ptr_arrayDatos[i]<<endl;
    }
}

void Trigonometrica::calcularSenCpp()
{
    for(int idy=0;idy<tam_prueba;idy++)
    {
        mat_Results[idy][0]=sin(ptr_arrayDatos[idy]);
//        cout<<"x: "<<ptr_arrayDatos[idy]<<", y: "<<mat_Results[idy][0]<<endl;
    }
}

void Trigonometrica::calcularCosCpp()
{
    for(int idy=0;idy<tam_prueba;idy++)
    {
        mat_Results[idy][1]=cos(ptr_arrayDatos[idy]);
    }
}

void Trigonometrica::calcularTanCpp()
{
//    double val_condicion=pi/2;
    for(int idy=0;idy<tam_prueba;idy++)
    {
//        if((ptr_arrayDatos[idy]>=-val_condicion)&&(ptr_arrayDatos[idy]<=val_condicion)){
            mat_Results[idy][2]=tan(ptr_arrayDatos[idy]);
//        }else mat_Results[idy][2]=0;
//        cout<<"x: "<<ptr_arrayDatos[idy];
//        cout<<", sen(x): "<<mat_Results[idy][0];
//        cout<<", cos(x): "<<mat_Results[idy][1];        
//        cout<<", tan(x): "<<mat_Results[idy][2]<<endl;
    }
}

long int fact (int n)
{
    long int resultado=1;
    for(int n_esimo=n;n_esimo>1;n_esimo--)
    {
        resultado=resultado*(long int)n_esimo;
    }
    return resultado;
}

//long int comb(int a, int b)
//{
//    long int resultado=0;
//    if(b==0||b==a) return 1;
//    else{
//        resultado=fact(a)/(fact(b)*fact(a-b));
//    }
//    return resultado;
//}

void Trigonometrica::bernoulli_A( int iMax, double* dB )
{
    dB[0] = 1.0;
    dB[1] = -0.5;
    dB[2] = 1.0 / 6.0;
 
    // Bernoulli para los elementos impares
    for(int j = 3; j <= iMax; j += 2 ) dB[j] = 0.0;
 
    // Relación recurrente para los indices pares de los números Bernoulli
    //
    for( int n = 2; n <= iMax/2; n++ )
    {
      double dSum = 0.0;
      long nBinom = 2*n - 1;  // El tipo se escoje como long
                              // para los resultados intermedios, no para todos
                              // if sizeof(int) == 2
 
      for( int r = 0; r <= n-2; r++ )
      {
        int r2 = 2*r + 2;
        double dItem = dB[r2]*dB[2*n-r2];
 
        dItem *= double( nBinom );
        dItem /= double( r2 );
 
        dSum += dItem;
 
        // coeficiente binomial calculado recurrentemente
        //
        nBinom *= (2*n-r2-1)*(2*n-r2);
        nBinom /= r2*(r2+1);
      }
      dB[2*n] = -double(2*n) / double(2*n+1) * dSum;
    }
}

void Trigonometrica::calcularSenMcLauren()
{
    cout<<"-------------------------calcularSenMcLauren: "<<truncar<<endl;
    for(int y_i=0;y_i<tam_prueba;y_i++)
    {
        for(int i=0;i<=truncar;i++)
        {
            long double division=(long double)pow(-1,i)/(long double)fact(2*i+1);
            mat_ResultsMcLauren[y_i][0]+=division*pow((long double)ptr_arrayDatos[y_i],(2*i+1));
        }    
    }
}

void Trigonometrica::calcularCosMcLauren()
{
    cout<<"-------------------------calcularCosMcLauren: "<<truncar<<endl;
    for(int y_i=0;y_i<tam_prueba;y_i++)
    {
        for(int i=0;i<=truncar;i++)
        {
            long double division=(long double)pow(-1,i)/(long double)fact(2*i);
            mat_ResultsMcLauren[y_i][1]+=division*pow((long double)ptr_arrayDatos[y_i], (2*i));
        }
    }
}

void Trigonometrica::calcularTanMcLauren()
{
    cout<<"-------------------------calcularTangMcLauren: "<<truncar<<endl;
    bernoulli_A(2*truncar,ptr_arrayBernoul);
    long double pow_cuatro=0;
    long double pow_cuatro_neg=0;
    long double factorial=0;
    long double division=0;
    for(int y_i=0;y_i<tam_prueba;y_i++)
    {
        for(int i=0;i<=truncar;i++)
        {
            pow_cuatro=(long double)pow(4,i);
            pow_cuatro_neg=pow_cuatro*(long double)pow(-1,i);
            factorial=(long double)fact(2*i);
//            cout<<"B(2*"<<i<<")= "<<ptr_arrayBernoul[2*i]<<", ";
//            cout<<"(-4)^n= "<<pow_cuatro_neg<<", ";
//            cout<<"(1-4^n)= "<<1-pow_cuatro<<", ";
//            cout<<"(2*"<<i<<")!= "<<factorial<<", ";
            division=(ptr_arrayBernoul[2*i]*pow_cuatro_neg*(1-pow_cuatro))/factorial;
//            cout<<"Division (B2n*((-4)^n)*(1-4^n))/2n!= "<<division<<endl;
            mat_ResultsMcLauren[y_i][2]+=division*pow((long double)ptr_arrayDatos[y_i], ((2*i)-1));
        }
//        cout<<"x: "<<ptr_arrayDatos[y_i]<<", yCpp:"<<mat_Results[y_i][2]<<", yMc: "<<mat_ResultsMcLauren[y_i][2]<<endl;
    }
}

void Trigonometrica::calcularErrorTrigos()
{
    int nPlusOne=0;
    long double pow_cuatro=0;
    long double pow_cuatro_neg=0;
    long double factorial=0;
    long double division=0;
            
    nPlusOne=truncar+1;
    
    
    long double divSen=(long double)pow(-1,nPlusOne)/(long double)fact((2*nPlusOne)+1);
    long double divCos=(long double)pow(-1,truncar+1)/(long double)fact(2*nPlusOne);
    
    pow_cuatro=(long double)pow(4,nPlusOne);
    pow_cuatro_neg=pow_cuatro*(long double)pow(-1,nPlusOne);
    factorial=(long double)fact(2*nPlusOne);
    division=(ptr_arrayBernoul[2*nPlusOne]*pow_cuatro_neg*(1-pow_cuatro))/factorial;
    cout<<"Division= "<<division<<endl;

    for(int y_i=0;y_i<tam_prueba;y_i++)
    {
        //Calcular para el seno:
        //
        mat_Error_trunc[y_i][0]+=divSen*pow((long double)ptr_arrayDatos[y_i], (2*(truncar+1)+1));
        //Calcular para el coseno:
        //
        mat_Error_trunc[y_i][1]+=divCos*pow((long double)ptr_arrayDatos[y_i], 2*((truncar+1)));
        //Calcular para el tangente:
        //
//            cout<<"B(2*"<<i<<")= "<<ptr_arrayBernoul[2*i]<<", ";
//            cout<<"(-4)^n= "<<pow_cuatro_neg<<", ";
//            cout<<"(1-4^n)= "<<1-pow_cuatro<<", ";
//            cout<<"(2*"<<i<<")!= "<<factorial<<", ";
//            cout<<"Division (B2n*((-4)^n)*(1-4^n))/2n!= "<<division<<endl;
        mat_Error_trunc[y_i][2]+=division*pow((long double)ptr_arrayDatos[y_i], ((2*nPlusOne)-1));
    }
}

void Trigonometrica::escribirResultados()
{
    fprintf(ptr_output,"**********************Se truncó en n= %i *********************\n",truncar);
    fprintf(ptr_output,"-----------------------FUNCIÓN SENO CPP-----------------------\n");
    fprintf(ptr_output,"--------------------------------------------------------------\n");
    fprintf(ptr_output, "x\t y\n");
    for(int i=0;i<tam_prueba;i++)
    {
        // Entradas fprintf: archivo, estructura (%f:float), datos a escribir.
        //
        fprintf(ptr_output,"%f\t ",ptr_arrayDatos[i]);
        fprintf(ptr_output,"%f\n",mat_Results[i][0]);
    }
    fprintf(ptr_output,"--------------------FUNCIÓN SENO MACLAURIN--------------------\n");
    fprintf(ptr_output,"--------------------------------------------------------------\n");
    fprintf(ptr_output, "x\t y\n");
    for(int i=0;i<tam_prueba;i++)
    {
        // Entradas fprintf: archivo, estructura (%f:float), datos a escribir.
        //
        fprintf(ptr_output,"%f\t ",ptr_arrayDatos[i]);
        fprintf(ptr_output,"%f\n",(double)mat_ResultsMcLauren[i][0]);
    }
    fprintf(ptr_output,"----------------------FUNCIÓN COSENO CPP----------------------\n");
    fprintf(ptr_output,"--------------------------------------------------------------\n");
    fprintf(ptr_output, "x\t y\n");
    for(int i=0;i<tam_prueba;i++)
    {
        // Entradas fprintf: archivo, estructura (%f:float), datos a escribir.
        //
        fprintf(ptr_output,"%f\t ",ptr_arrayDatos[i]);
        fprintf(ptr_output,"%f\n",mat_Results[i][1]);
    }
    fprintf(ptr_output,"--------------------FUNCIÓN COSENO MCLAURIN-------------------\n");
    fprintf(ptr_output,"--------------------------------------------------------------\n");
    fprintf(ptr_output, "x\t y\n");
    for(int i=0;i<tam_prueba;i++)
    {
        // Entradas fprintf: archivo, estructura (%f:float), datos a escribir.
        //
        fprintf(ptr_output,"%f\t ",ptr_arrayDatos[i]);
        fprintf(ptr_output,"%f\n",(double)mat_ResultsMcLauren[i][1]);
    }
    fprintf(ptr_output,"---------------------FUNCIÓN TANGENTE CPP---------------------\n");
    fprintf(ptr_output,"--------------------------------------------------------------\n");
    fprintf(ptr_output, "x\t y\n");
    for(int i=0;i<tam_prueba;i++)
    {
        // Entradas fprintf: archivo, estructura (%f:float), datos a escribir.
        //
        fprintf(ptr_output,"%f\t ",ptr_arrayDatos[i]);
        fprintf(ptr_output,"%f\n",mat_Results[i][2]);
    }
    fprintf(ptr_output,"-------------------FUNCIÓN TANGENTE MCLAURIN------------------\n");
    fprintf(ptr_output,"--------------------------------------------------------------\n");
    fprintf(ptr_output, "x\t y\n");
    for(int i=0;i<tam_prueba;i++)
    {
        // Entradas fprintf: archivo, estructura (%f:float), datos a escribir.
        //
        fprintf(ptr_output,"%f\t ",ptr_arrayDatos[i]);
        fprintf(ptr_output,"%f\n",(double)mat_ResultsMcLauren[i][2]);
    }
    fprintf(ptr_output,"---------------------FUNCIÓN ERROR MCLAURIN-------------------\n");
    fprintf(ptr_output,"--------------------------------------------------------------\n");
    char funcion[20];
    
    for(int e=0;e<3;e++)
    {
        switch (e)
        {
            case 0:
                strcpy(funcion,"SENO");
                break;
            case 1: 
                strcpy(funcion,"COSENO");
                break;
            case 2: 
                strcpy(funcion,"TANGENTE");
                break;
        }
        fprintf(ptr_output, "---------------------------FUNCIÓN %s-------------------------\n",funcion);
        fprintf(ptr_output, "x\t r(x)\n");        
        for(int i=0;i<tam_prueba;i++)
        {
            // Entradas fprintf: archivo, estructura (%f:float), datos a escribir.
            //
            fprintf(ptr_output,"%f\t ",ptr_arrayDatos[i]);
            fprintf(ptr_output,"%f\n",(double)mat_Error_trunc[i][e]);
        }
    }
    fclose(ptr_output); 
}

